//GNU C библиотека.
#include <linux/videodev.h>


//Библиотека Qt.
#include <QtGui>


//Внутренняя библиотека.
#include "devparamswidget.h"
#include "devmanager.h"


//===========================================================================//
//=Заголовок: DevParamsWidget::DevParamsWidget() - public
//=Параметры:
//=Описание: Конструктор.
//===========================================================================//
DevParamsWidget::DevParamsWidget(DevManager *devmanager, QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f)
{
devManager = devmanager;
connect(devManager, SIGNAL(devicesSelected()), this, SLOT(slotLoadParams()));

//Создать группу виджетов для настройки параметров видеоустройства.
QGroupBox *paramsgrpbox = createParamsWidgets();

//Создать группу виджетов для настройки буферизации видеокадров.
QGroupBox *bufferinggrpbox = createBufferingWidgets();

//Создать группу виджетов для настройки параметров видеокодека.
QGroupBox *codecgrpbox = createCodecWidgets();

//Создать группу виджетов для настройки параметров записи в файл.
QGroupBox *fwritergrpbox = createFileWriterWidgets();

QLabel *bevellabel = NULL;
QHBoxLayout *managebutlayout = NULL;
QPushButton *closebut = NULL;
if(isWindow())
	{
	//Создать разделительную линию.
	bevellabel = new QLabel(this);
	bevellabel->setFrameStyle(QFrame::HLine | QFrame::Sunken);

	//Создать кнопку.
	closebut = new QPushButton(tr("Закрыть"), this);
	connect(closebut, SIGNAL(clicked()), this, SLOT(close()));

	//Создать менеджер размещения.
	managebutlayout = new QHBoxLayout();
	managebutlayout->setMargin(2); managebutlayout->setSpacing(2);
	managebutlayout->addStretch(1);
	managebutlayout->addWidget(closebut);
}

//Создать главный менеджер размещения.
QGridLayout *mainlayout = new QGridLayout(this);
mainlayout->setMargin(5); mainlayout->setSpacing(5);
mainlayout->addWidget(paramsgrpbox, 0, 0);
mainlayout->addWidget(bufferinggrpbox, 0, 1);
mainlayout->addWidget(codecgrpbox, 1, 0, 1, 2);
mainlayout->addWidget(fwritergrpbox, 2, 0, 1, 2);
if(bevellabel && managebutlayout && closebut)
	{
	mainlayout->addWidget(bevellabel, 3, 0, 1, 2);
	mainlayout->addLayout(managebutlayout, 4, 0, 1, 2);
}
mainlayout->setRowStretch(5, 1);

//Загрузить параметры устройства.
slotLoadParams();
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::clearWidgets() - public
//=Параметры:
//=Описание: Функция очистки виджетов.
//===========================================================================//
void DevParamsWidget::clearWidgets()
{
inputCBox->clear(); standardCBox->clear();
pixfmtCBox->clear(); resCBox->clear();

cachePBar->setMaximum(0);
plusCacheTBut->setEnabled(false);
minusCacheTBut->setEnabled(false);

frameratePBar->setMaximum(0);
framerateSlider->setEnabled(false);
framerateSlider->setValue(0);

codecCBox->clear();

formatFWriterCBox->clear();
}


//===========================================================================//
//=Заголовок: QGroupBox *DevParamsWidget::createParamsWidgets() - private
//=Параметры:
//=Описание: Функция создания группы виджетов для настройки
//=          параметров видеоустройства.
//===========================================================================//
QGroupBox *DevParamsWidget::createParamsWidgets()
{
QGroupBox *grpbox = new QGroupBox(tr("Параметры"), this);

//Создать виджеты управления видеовходом.
QLabel *inputlabel = new QLabel(tr("Видеовход:"), grpbox);
inputCBox = new QComboBox(grpbox);
connect(inputCBox, SIGNAL(activated(int)), this, SLOT(slotInputActivated(int)));

//Создать менеджер размещения.
QVBoxLayout *inputlayout = new QVBoxLayout();
inputlayout->setMargin(2); inputlayout->setSpacing(2);
inputlayout->addWidget(inputlabel);
inputlayout->addWidget(inputCBox);

//Создать виджеты управления видеостандартом.
QLabel *standardlabel = new QLabel(tr("Видеостандарт:"), grpbox);
standardCBox = new QComboBox(grpbox);
connect(standardCBox, SIGNAL(activated(int)), this, SLOT(slotStandardActivated(int)));

//Создать менеджер размещения.
QVBoxLayout *standardlayout = new QVBoxLayout();
standardlayout->setMargin(2); standardlayout->setSpacing(2);
standardlayout->addWidget(standardlabel);
standardlayout->addWidget(standardCBox);

//Создать виджеты управления видеоформатом.
QLabel *pixfmtlabel = new QLabel(tr("Видеоформат:"), grpbox);
pixfmtCBox = new QComboBox(grpbox);
pixfmtCBox->setEnabled(false);
connect(pixfmtCBox, SIGNAL(activated(int)), this, SLOT(slotPixFmtActivated(int)));

//Создать менеджер размещения.
QVBoxLayout *pixfmtlayout = new QVBoxLayout();
pixfmtlayout->setMargin(2); pixfmtlayout->setSpacing(2);
pixfmtlayout->addWidget(pixfmtlabel);
pixfmtlayout->addWidget(pixfmtCBox);

//Создать виджеты управления видеоразрешением.
QLabel *reslabel = new QLabel(tr("Видеоразрешение:"), grpbox);
resCBox = new QComboBox(grpbox);
connect(resCBox, SIGNAL(activated(int)), this, SLOT(slotResolutionActivated(int)));

//Создать менеджер размещения.
QVBoxLayout *reslayout = new QVBoxLayout();
reslayout->setMargin(2); reslayout->setSpacing(2);
reslayout->addWidget(reslabel);
reslayout->addWidget(resCBox);

//Создать главный менеджер размещения.
QVBoxLayout *mainlayout = new QVBoxLayout(grpbox);
mainlayout->setMargin(5); mainlayout->setSpacing(5);
mainlayout->addLayout(inputlayout);
mainlayout->addLayout(standardlayout);
mainlayout->addLayout(pixfmtlayout);
mainlayout->addLayout(reslayout);

return grpbox;
}


//===========================================================================//
//=Заголовок: QGroupBox *DevParamsWidget::createBufferingWidgets() - private
//=Параметры:
//=Описание: Функция создания группы виджетов для настройки
//=          буферизации видеокадров.
//===========================================================================//
QGroupBox *DevParamsWidget::createBufferingWidgets()
{
QGroupBox *grpbox = new QGroupBox(tr("Буферизация"), this);

//Создать виджеты управления кадровым периодом.
QLabel *frameratelabel = new QLabel(tr("Период"), grpbox);
frameratePBar = new QProgressBar(grpbox);
frameratePBar->setOrientation(Qt::Vertical);
frameratePBar->setRange(1, 50);
frameratePBar->setFormat(tr("%v к/с"));
connect(devManager, SIGNAL(deviceFramerateChanged(int)), frameratePBar, SLOT(setValue(int)));
framerateSlider = new QSlider(Qt::Vertical, grpbox);
framerateSlider->setRange(2, 50);
framerateSlider->setSingleStep(1);
framerateSlider->setValue(1);
framerateSlider->setTickPosition(QSlider::TicksAbove);
connect(framerateSlider, SIGNAL(sliderMoved(int)), this, SLOT(slotMaxFramerateChange(int)));

//Создать менеджер размещения.
QGridLayout *frameratelayout = new QGridLayout();
frameratelayout->setMargin(2); frameratelayout->setSpacing(2);
frameratelayout->addWidget(frameratelabel, 0, 0, 1, 2);
frameratelayout->addWidget(frameratePBar, 1, 0);
frameratelayout->addWidget(framerateSlider, 1, 1);

//Создать виджеты управления кадровым кэшом.
QLabel *cachelabel = new QLabel(tr("Кэш"), grpbox);
plusCacheTBut = new QToolButton(grpbox);
plusCacheTBut->setFixedSize(28, 28);
plusCacheTBut->setIcon(QIcon(":/images/plus.png"));
connect(plusCacheTBut, SIGNAL(clicked()), this, SLOT(slotCachePlus()));
minusCacheTBut = new QToolButton(grpbox);
minusCacheTBut->setFixedSize(28, 28);
minusCacheTBut->setIcon(QIcon(":/images/minus.png"));
connect(minusCacheTBut, SIGNAL(clicked()), this, SLOT(slotCacheMinus()));

cachePBar = new QProgressBar(grpbox);
cachePBar->setOrientation(Qt::Vertical);
cachePBar->setRange(2, VIDEO_MAX_FRAME);
cachePBar->setFormat(tr("%v к"));

//Создать менеджер размещения.
QVBoxLayout *cachelayout = new QVBoxLayout();
cachelayout->setMargin(2); cachelayout->setSpacing(2);
cachelayout->addWidget(cachelabel);
cachelayout->addWidget(plusCacheTBut);
cachelayout->addWidget(cachePBar);
cachelayout->addWidget(minusCacheTBut);

//Создать главный менеджер размещения.
QHBoxLayout *mainlayout = new QHBoxLayout(grpbox);
mainlayout->setMargin(5); mainlayout->setSpacing(5);
mainlayout->addLayout(frameratelayout);
mainlayout->addLayout(cachelayout);

return grpbox;
}


//===========================================================================//
//=Заголовок: QGroupBox *DevParamsWidget::createCodecWidgets() - private
//=Параметры:
//=Описание: Функция создания группы виджетов для настройки
//=          параметров видеокодека.
//===========================================================================//
QGroupBox *DevParamsWidget::createCodecWidgets()
{
QGroupBox *grpbox = new QGroupBox(tr("Кодек"), this);

//Создать виджет выбора видеокодека.
codecCBox = new QComboBox(grpbox);
connect(codecCBox, SIGNAL(activated(int)), this, SLOT(slotCodecActivated(int)));

//Создать менеджер размещения.
QVBoxLayout *codeclayout = new QVBoxLayout();
codeclayout->setMargin(2); codeclayout->setSpacing(2);
codeclayout->addWidget(codecCBox);

//Создать главный менеджер размещения.
QVBoxLayout *mainlayout = new QVBoxLayout(grpbox);
mainlayout->setMargin(5); mainlayout->setSpacing(5);
mainlayout->addLayout(codeclayout);

return grpbox;
}


//===========================================================================//
//=Заголовок: QGroupBox *DevParamsWidget::createFileWriterWidgets() - private
//=Параметры:
//=Описание: Функция создания группы виджетов для настройки
//=          параметров записи в файл.
//===========================================================================//
QGroupBox *DevParamsWidget::createFileWriterWidgets()
{
QGroupBox *grpbox = new QGroupBox(tr("Запись в файл"), this);

//Создать виджет выбора формата видеофайла.
formatFWriterCBox = new QComboBox(grpbox);

//Создать менеджер размещения.
QVBoxLayout *formatlayout = new QVBoxLayout();
formatlayout->setMargin(2); formatlayout->setSpacing(2);
formatlayout->addWidget(formatFWriterCBox);

//Создать главный менеджер размещения.
QVBoxLayout *mainlayout = new QVBoxLayout(grpbox);
mainlayout->setMargin(5); mainlayout->setSpacing(5);
mainlayout->addLayout(formatlayout);

return grpbox;
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::updateParamWidget() - private
//=Параметры:
//=Описание: Функция обновления виджета параметров видеоустройства.
//===========================================================================//
void DevParamsWidget::updateParamWidget(QHash<int, QVariant> hash, QVariant curvalue, QComboBox *cbox, bool sort)
{
cbox->clear();

if(hash.isEmpty()) return;

//Заполнить визуальный список.
QHashIterator<int, QVariant> hash_i(hash);
while(hash_i.hasNext())
	{
	hash_i.next();
	cbox->addItem(hash_i.value().toString(), hash_i.key());
}
if(curvalue.toInt() == -1) cbox->addItem(tr("Множественное значение"), curvalue);
if(sort) cbox->model()->sort(0);

//Установить текущее значение в визуальном списке.
for(int i = 0; i < cbox->count(); ++i)
	{
	if(cbox->itemData(i) == curvalue.toInt())
		cbox->setCurrentIndex(i);
}
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::slotLoadParams() - private slots
//=Параметры:
//=Описание: Слот загрузки параметров видеоустройства.
//===========================================================================//
void DevParamsWidget::slotLoadParams()
{
//Получить параметры устройства.
QHash<int, QVariant> inputshash, standardshash, pixformatshash, reshash;
devManager->getListParam(DevParam::GET_LIST_INPUTS, &inputshash);
devManager->getListParam(DevParam::GET_LIST_STANDARDS, &standardshash);
devManager->getListParam(DevParam::GET_LIST_PIXFORMATS, &pixformatshash);
devManager->getListParam(DevParam::GET_LIST_RESOLUTIONS, &reshash);

QVariant input, standard, pixformat, resolution;
devManager->getParam(DevParam::GET_INPUT, &input);
devManager->getParam(DevParam::GET_STANDARD, &standard);
devManager->getParam(DevParam::GET_PIXFORMAT, &pixformat);
devManager->getParam(DevParam::GET_RESOLUTION, &resolution);

//Обновить виджеты параметров устройства.
updateParamWidget(inputshash, input, inputCBox);
updateParamWidget(standardshash, standard, standardCBox, true);
updateParamWidget(pixformatshash, pixformat, pixfmtCBox, true);
updateParamWidget(reshash, resolution, resCBox);

//Получить параметры буферизации.
QVariant maxframescache, framescache, maxframerate, framerate;
devManager->getParam(DevParam::GET_MAX_FRAMESCACHE, &maxframescache);
devManager->getParam(DevParam::GET_FRAMESCACHE, &framescache);
devManager->getParam(DevParam::GET_MAX_FRAMERATE, &maxframerate);
devManager->getParam(DevParam::GET_FRAMERATE, &framerate);

//Обновить виджеты параметров буферизации.
cachePBar->reset();

if(maxframescache.toInt() == -1 || maxframescache.toInt() == 0 || framescache.toInt() == -1 || framescache.toInt() == 0)
	{
	cachePBar->setMaximum(0);
	plusCacheTBut->setEnabled(false);
	minusCacheTBut->setEnabled(false);
}
else {
	cachePBar->setMaximum(maxframescache.toInt());
	cachePBar->setValue(framescache.toInt());

	plusCacheTBut->setEnabled(true);
	minusCacheTBut->setEnabled(true);
}

if(maxframerate.toInt() == -1 || maxframerate.toInt() == 0)
	{
	frameratePBar->setMaximum(0);
	framerateSlider->setValue(1);
	framerateSlider->setEnabled(false);
}
else {
	frameratePBar->setMaximum(50);
	frameratePBar->setValue(framerate.toInt());
	framerateSlider->setEnabled(true);
	framerateSlider->setValue(maxframerate.toInt());
}

//Получить параметры видеокодека.
QHash<int, QVariant> codechash;
devManager->getListParam(DevParam::GET_LIST_VIDEOCODEC_NAMES, &codechash);

QVariant codeccur;
devManager->getParam(DevParam::GET_VIDEOCODEC_CURRENT, &codeccur);

//Обновить виджеты параметров видеокодека.
updateParamWidget(codechash, codeccur, codecCBox, true);

//Получить параметры записи в файл.
QHash<int, QVariant> formatfwriterhash;
devManager->getListParam(DevParam::GET_LIST_FILEWRITER_FORMATS, &formatfwriterhash);

formatFWriterCBox->clear();

//Заполнить визуальный список.
QHashIterator<int, QVariant> hash_i(formatfwriterhash);
while(hash_i.hasNext())
	{
	hash_i.next();
	formatFWriterCBox->addItem(hash_i.value().toString(), hash_i.key());
}
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::slotInputActivated() - private slots
//=Параметры:
//=Описание: Слот смены видеовхода.
//===========================================================================//
void DevParamsWidget::slotInputActivated(int index)
{
//Если выбрано "Множественное значение"...
if(inputCBox->itemData(index).toInt() == -1) return;
devManager->setParam(DevParam::SET_INPUT, inputCBox->itemData(index));
slotLoadParams();
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::slotStandardActivated() - private slots
//=Параметры:
//=Описание: Слот смены видеостандарта.
//===========================================================================//
void DevParamsWidget::slotStandardActivated(int index)
{
if(standardCBox->itemData(index).toInt() == -1) return;
devManager->setParam(DevParam::SET_STANDARD, standardCBox->itemData(index));
slotLoadParams();
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::slotPixFmtActivated() - private slots
//=Параметры:
//=Описание: Слот смены видеоформата.
//===========================================================================//
void DevParamsWidget::slotPixFmtActivated(int index)
{
if(pixfmtCBox->itemData(index).toInt() == -1) return;
devManager->setParam(DevParam::SET_PIXFORMAT, pixfmtCBox->itemData(index));
slotLoadParams();
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::slotResolutionActivated() - private slots
//=Параметры:
//=Описание: Слот смены видеоразрешения.
//===========================================================================//
void DevParamsWidget::slotResolutionActivated(int index)
{
if(resCBox->itemData(index).toInt() == -1) return;
devManager->setParam(DevParam::SET_RESOLUTION, resCBox->itemData(index));
slotLoadParams();
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::slotCachePlus() - private slots
//=Параметры:
//=Описание: Слот увеличения кол-ва видеобуферов.
//===========================================================================//
void DevParamsWidget::slotCachePlus()
{
devManager->setParam(DevParam::SET_FRAMESCACHE, cachePBar->value() + 1);
slotLoadParams();
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::slotCacheMinus() - private slots
//=Параметры:
//=Описание: Слот уменьшения кол-ва видеобуферов.
//===========================================================================//
void DevParamsWidget::slotCacheMinus()
{
devManager->setParam(DevParam::SET_FRAMESCACHE, cachePBar->value() - 1);
slotLoadParams();
}


//===========================================================================//
//=Заголовок: void DevParamsWidget::slotMaxFramerateChange() - private slots
//=Параметры:
//=Описание: Слот смены максимального уровня кадрового периода.
//===========================================================================//
void DevParamsWidget::slotMaxFramerateChange(int value)
{devManager->setParam(DevParam::SET_MAX_FRAMERATE, value);}


//===========================================================================//
//=Заголовок: void DevParamsWidget::slotCodecActivated() - private slots
//=Параметры:
//=Описание: Слот смены видеокодека.
//===========================================================================//
void DevParamsWidget::slotCodecActivated(int index)
{
if(codecCBox->itemData(index).toInt() == -1) return;
devManager->setParam(DevParam::SET_VIDEOCODEC_CURRENT, codecCBox->itemData(index));
slotLoadParams();
}
